package org.yunai.yfserver.persistence.async;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.yunai.yfserver.async.IIoSerialOperation;
import org.yunai.yfserver.common.constants.CommonErrorLogInfo;
import org.yunai.yfserver.persistence.PersistenceObject;
import org.yunai.yfserver.persistence.orm.Entity;
import org.yunai.yfserver.persistence.orm.mybatis.SaveMapper;

/**
 * 保存或者更新对象到数据库中
 * User: yunai
 * Date: 13-4-9
 * Time: 下午4:33
 */
public class SavePersistenceObjectOperation<E extends Entity<?>, P extends PersistenceObject<?, E>> implements IIoSerialOperation {

    private static final Logger LOGGER = org.yunai.yfserver.common.LoggerFactory.getLogger(org.yunai.yfserver.common.LoggerFactory.Logger.async, DeletePersistenceObjectOperation.class);

    /**
     * 业务对象
     */
    private final P persistenceObject;
    /**
     * 实体对象
     */
    private final E entity;
    /**
     * 实体类数据库Mapper
     */
    private final SaveMapper<E> mapper;
    /**
     * 判断是否为保存操作
     */
    private volatile boolean update;

    public SavePersistenceObjectOperation(P persistenceObject, SaveMapper mapper) {
        this.persistenceObject = persistenceObject;
        this.entity = persistenceObject.toEntity();
        this.mapper = mapper;
    }

    @Override
    public State doStart() {
        this.update = persistenceObject.isInDB();
        if (!persistenceObject.isInDB()) {
            persistenceObject.setInDB(true);
        }
        return State.STARTED;
    }

    @Override
    public State doIo() {
        try {
            if (update) {
                mapper.update(entity);
            } else {
                mapper.insert(entity);
            }
        } catch (Exception e) {
            if (!update) {
                persistenceObject.setInDB(false);
            }
            LOGGER.error("[doIo][{}][{}] entity[{}] dao[{}] error[{}].", CommonErrorLogInfo.DB_OPERATE_FAIL, update ? "UPDATE" : "INSERT",
                    JSON.toJSONString(entity), mapper, ExceptionUtils.getStackTrace(e));
            return State.FINISHED;
        }
        return State.IO_DONE;
    }

    @Override
    public State doFinish() {
        return State.FINISHED;
    }

    @Override
    public Integer getSerialKey() {
        return persistenceObject.getUnitId();
    }
}
